<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <title>Field Test Suite</title>
    <script type="text/javascript" src="../js/inputex-loader.js"></script>
</head>
<body class="yui-skin-sam">
<h1>
    <script>document.write(document.title)</script>
</h1>

<div id="test"></div>

<script type="text/javascript">
inputEx.YUI({base:'../lib/yui3/',inputExBase:'../'}).use('node', 'console', 'yuitest', 'field', function(Y) {
    Y.namespace('inputEx.tests')
    Y.inputEx.tests.FieldTests = new Y.Test.Case({
        name: 'Field Tests',
        setUp:function() {
            this.data = {
                createTextField:  function(container) {
                    var field = Y.Node.create('<input id="' + this.getID() + '-field" type="text"/>')
                    if (this.get('name')) field.set('name', this.get('name'))
                    if (this.get('value')) field.set('value', this.get('value'))
                    container.appendChild(field)
                    this._inputEl = field
                }
            }
            Y.get('#test').set('innerHTML', '')
        },
        tearDown:function() {
            delete this.data;
        },


        testLoader:function() {
            Y.Assert.isTrue(typeof(Y.inputEx) !== 'undefined')
            Y.Assert.isTrue(typeof(Y.inputEx.Field) !== 'undefined')
        },

        testConstructor:function() {
            var field = new Y.inputEx.Field()
            Y.Assert.isNotUndefined(field)
            Y.Assert.isInstanceOf(Y.inputEx.Field, field, 'The field is not a Y.inputEx.Field')
        },

        testID:function() {
            var container = Y.Node.create('<div id="testInputElSync"></div>')
            Y.get('#test').appendChild(container)
            var field;

            // id only
            field = new Y.inputEx.Field({id:'idAsID'})
            Y.Assert.areEqual('idAsID', field.get('id'))
            field.renderComponent = this.data.createTextField;
            field.render(container)
            Y.Assert.areEqual('idAsID', field.get('boundingBox').get('id'))
            container.set('innerHTML', '')

            // boundingBox default ID
            var boundingBox = Y.Node.create('<div id="domID"></div>')
            container.appendChild(boundingBox)
            field = new Y.inputEx.Field({boundingBox:'#domID'}) //both String ID and node are ok
            field.renderComponent = this.data.createTextField;
            field.render(container)
            Y.Assert.areEqual('domID', field.get('boundingBox').get('id'))
            Y.Assert.areEqual('domID', field.get('id'))
            container.set('innerHTML', '')

            // name only
            field = new Y.inputEx.Field({name:'nameAsID'})
            field.renderComponent = this.data.createTextField;
            field.render(container)
            Y.Assert.areEqual('nameAsID', field.get('boundingBox').get('id'))
            Y.Assert.areEqual('nameAsID', field.get('id'))
            container.set('innerHTML', '')

            // absense, id shall prefix with 'inputEx'
            field = new Y.inputEx.Field()
            field.renderComponent = this.data.createTextField;
            field.render(container)
            Y.Assert.areEqual('inputEx-', field.get('boundingBox').get('id').substring(0, 8))
            Y.Assert.areEqual('inputEx-', field.get('id').substring(0, 8))

            container.set('innerHTML', '')
        },

        /**
         * boundingBox
         *   contentBox
         *     labelBox
         *       label
         *     inputBox
         *       {renderComponent}
         *       description div
         *     message div
         *     lineBreak
         *
         * Remarks: this method doesn't test classes set by state, e.g. invalid, focus, typeInvite etc.
         */
        testDOMStructureAndClasses:function() {
            var container = Y.Node.create('<div id="testDOMStructureAndClasses"></div>')
            Y.get('#test').appendChild(container)
            var field = new Y.inputEx.Field({id:'field0',value:'value',label:'label',
                message:'message',description:'description',
                validator:[{minLength:20,message:'min length is {minLength}'}],
                showMsg:true,
                boundingBoxClass:'boundingBoxClass',contentBoxClass:'contentBoxClass'})
            field.renderComponent = this.data.createTextField;
            field.render(container);

            var id = field.get('id')

            //boundingBox
            Y.Assert.isInstanceOf(Y.Node, container.query('div'))
            Y.Assert.areEqual(id, container.query('div').getAttribute('id'))
            Y.Assert.isTrue(container.query('div').hasClass('yui-widget'))
            Y.Assert.isTrue(container.query('div').hasClass('yui-field'))
            Y.Assert.isTrue(container.query('div').hasClass('boundingBoxClass'))
            //TODO add another test case for state classes

            //contentBox
            var contentBox = container.query('div.boundingBoxClass > div')
            Y.Assert.isInstanceOf(Y.Node, contentBox)
            Y.Assert.areEqual(id + '-content', contentBox.getAttribute('id'))
            Y.Assert.isTrue(contentBox.hasClass('yui-field-content'), 'shall have class "yui-field-content"')
            Y.Assert.isTrue(contentBox.hasClass('contentBoxClass'), 'shall have class "contentBoxClass"')

            //label: div.class, label.id, label.for, label.text
            var labelBox = container.query('div.boundingBoxClass > div.contentBoxClass > div.inputEx-label')
            Y.Assert.isInstanceOf(Y.Node, labelBox)
            Y.Assert.isTrue(labelBox.hasClass('inputEx-label'), 'shall have class "inputEx-label"')
            Y.Assert.isInstanceOf(Y.Node, labelBox.query('label'))
            Y.Assert.areEqual(id + '-label', labelBox.query('label').getAttribute('id'))
            Y.Assert.areEqual(id + '-field', labelBox.query('label').getAttribute('for'))
            Y.Assert.areEqual(field.get('label'), labelBox.query('label').get('text'))

            // field
            // Remarks: renderComponent is a dummy implementation to avoid error, DOM structure shall not be tested

            var fieldBox = container.query('div.boundingBoxClass > div.contentBoxClass > div.inputEx-Field')
            Y.Assert.isInstanceOf(Y.Node, fieldBox, 'fieldBox is not a Node')
            Y.Assert.isTrue(fieldBox.hasClass('inputEx-Field'), 'shall have class "inputEx-Field"')
            Y.Assert.isInstanceOf(Y.Node, fieldBox.query('div.inputEx-description'), 'description is not a Node')
            Y.Assert.areEqual(id + '-description', fieldBox.query('div.inputEx-description').getAttribute('id'))
            Y.Assert.isTrue(fieldBox.query('div.inputEx-description').hasClass('inputEx-description'))

            //message
            var message = container.query('div.boundingBoxClass > div.contentBoxClass > div.inputEx-message')
            Y.Assert.isInstanceOf(Y.Node, message, 'message element is not a Node')
            Y.Assert.isTrue(message.hasClass('inputEx-message'), 'shall have class "inputEx-message"')
            Y.Assert.areEqual('min length is 20', message.get('text'))
        },

        /**
         * This test is to ensure widget behavior is correctly inherited
         */
        testWidgetAttributes:function() {
            var container = Y.Node.create('<div id="test_widgetAttributes"></div>')
            Y.get('#test').appendChild(container)
            var field = new Y.inputEx.Field()
            field.renderComponent = this.data.createTextField;

            // 'rendered'
            Y.Assert.isFalse(field.get('rendered'), 'rendered shall be false before render()')
            field.render(container);
            Y.Assert.isTrue(field.get('rendered'), 'rendered shall be true after render()')

            // 'hasFocus'
            Y.Assert.isFalse(field.get('hasFocus'), 'hasFocus shall be false before focus()')
            field.focus();
            Y.Assert.isTrue(field.get('hasFocus'), 'hasFocus shall be true after focus()')
        } ,

        testEvent_Change:function() {
            var container = Y.Node.create('<div id="testEvent_Change"></div>')
            Y.get('#test').appendChild(container)
            var field = new Y.inputEx.Field({value:'oldValue'})
            field.renderComponent = this.data.createTextField;
            field.render(container)

            Y.Assert.areEqual('oldValue', field.get('value'))

            field.on("change", function(evt, n, o) { // both 'change' and 'field:change' could be used
                this.resume(function() {
                    Y.Assert.areEqual('newValue', n)
                    Y.Assert.areEqual('oldValue', o)
                    Y.Assert.areEqual('oldValue', field.get('value'));// on change is called during the change, so the value is not updated yet
                });
            }, this, true);

            field._inputEl = Y.Node.create('<input value="' + field.get('value') + '"/>') //dummy inputEl for test
            field.set('value', 'newValue')
            Y.Assert.areEqual('newValue', field.get('value'))
            Y.Assert.areEqual('newValue', field._inputEl.get('value'), 'input change by api is not sync to the inputEl')
            this.wait(2000);
        },

        testValidateAfterRendered:function() {
            var container = Y.Node.create('<div id="testValidateAfterRendered"></div>')
            Y.get('#test').appendChild(container)
            var field = new Y.inputEx.Field({value:10,validateOnRender:true,validator:[{min:20}]})//validateAfterRendered default to true
            field.renderComponent = this.data.createTextField;
            field.render(container)
            Y.Assert.isTrue(field._validated, 'shall have been validated on render')
            Y.Assert.isTrue(field._violations.length > 0)
        },

        testValidateOnChangeAttribute:function() {
            var container = Y.Node.create('<div id="testValidateOnChangeAttribute"></div>')
            Y.get('#test').appendChild(container)
            var field = new Y.inputEx.Field({value:10,validateOnRender:false,validateOnChange:true,validator:[{min:20}]})
            field.renderComponent = this.data.createTextField;
            field.render(container)

            //upon rendered, the field hv not been validated
            Y.Assert.isFalse(field._validated, 'shall not validate on render')
            Y.Assert.areEqual(0, field._violations.length)

            //set flag to true and update value to trigger validation
            field.set('validateOnChange', true)
            field.set('value', 15)
            Y.Assert.isTrue(field._validated)
            Y.Assert.isTrue(field._violations.length > 0)

            // set to a valid value
            field.set('value', 20)
            Y.Assert.areEqual(0, field._violations.length)

            //set flag to false
            field.set('validateOnChange', false)
            field.set('value', 15)
            Y.Assert.areEqual(0, field._violations.length); //onchange validation is disabled
        },

        testFocusBlur:function() {
            var container = Y.Node.create('<div id="testFocusBlur"></div>')
            Y.get('#test').appendChild(container)
            var field = new Y.inputEx.Field({value:'oldValue'})
            field.renderComponent = this.data.createTextField;
            field.render(container)

            // init state
            Y.Assert.isFalse(field.get('hasFocus'))
            Y.Assert.isTrue(field.get('boundingBox').hasClass('inputEx-empty'), 'boundingBox shall have inputEx-empty class after rendered')
            Y.Assert.isFalse(field.get('boundingBox').hasClass('inputEx-focused'), 'boundingBox shall NOT have inputEx-focused class after rendered')

            field.focus();
            Y.Assert.isTrue(field.get('hasFocus'))
            Y.Assert.isTrue(field.get('boundingBox').hasClass('inputEx-focused'), 'boundingBox shall have inputEx-focused class after focused')
            Y.Assert.isFalse(field.get('boundingBox').hasClass('inputEx-empty'), 'boundingBox shall NOT have inputEx-empty class after focused')

            field.blur();
            Y.Assert.isFalse(field.get('hasFocus'))
            Y.Assert.isFalse(field.get('boundingBox').hasClass('inputEx-focused'), 'boundingBox shall NOT have inputEx-focused class after blured')
            Y.Assert.isTrue(field.get('boundingBox').hasClass('inputEx-empty'), 'boundingBox shall have inputEx-empty class after blured')
        },

        testHideShow:function() {
            var container = Y.Node.create('<div id="testHideShow"></div>')
            Y.get('#test').appendChild(container)
            var field = new Y.inputEx.Field({value:'defaultValue',validateOnRender:false,validateOnChange:false})
            field.renderComponent = this.data.createTextField;
            field.render(container)

            // default, after rendered
            Y.Assert.isFalse(field.get('boundingBox').hasClass('yui-field-hidden'), 'shall not be hidden right after rendered')
            Y.Assert.areEqual('block', field.get('boundingBox').getStyle('display'))

            // hide
            field.hide()
            Y.Assert.isTrue(field.get('boundingBox').hasClass('yui-field-hidden'), 'boundingBox shall be hidden')
            Y.Assert.areEqual('none', field.get('boundingBox').getStyle('display'))

            // show
            field.show()
            Y.Assert.isFalse(field.get('boundingBox').hasClass('yui-field-hidden'), 'boundingBox not be hidden after show()')
            Y.Assert.areEqual('block', field.get('boundingBox').getStyle('display'))
        },

        testEnableDisable:function() {
            var container = Y.Node.create('<div id="testEnableDisable"></div>')
            Y.get('#test').appendChild(container)
            var field = new Y.inputEx.Field({value:'defaultValue',validateOnRender:false,validateOnChange:false})
            field.renderComponent = this.data.createTextField;
            field.render(container)

            // default, after rendered
            Y.Assert.isFalse(field.get('boundingBox').hasClass('yui-field-disabled'), 'shall not be disabled right after rendered')
            Y.Assert.isFalse(field._getInputEl().get('disabled'))

            // disable
            field.disable()
            Y.Assert.isTrue(field.get('boundingBox').hasClass('yui-field-disabled'), 'shall not be disabled right after rendered')
            Y.Assert.isTrue(field._getInputEl().get('disabled'))

            // enable
            field.enable()
            Y.Assert.isFalse(field.get('boundingBox').hasClass('yui-field-disabled'), 'shall not be disabled right after rendered')
            Y.Assert.isFalse(field._getInputEl().get('disabled'))
        },

        testInputElSync:function() {
            var container = Y.Node.create('<div id="testInputElSync"></div>')
            Y.get('#test').appendChild(container)
            var field = new Y.inputEx.Field({value:'defaultValue',validateOnRender:false,validateOnChange:false})
            field.renderComponent = this.data.createTextField;
            field.render(container)

            Y.Assert.areEqual(field.get('value'), field._getInputEl().get('value'))

            //change by API
            field.set('value', 'setByAPI')
            Y.Assert.areEqual('setByAPI', field._getInputEl().get('value'))

            //change by field
            //field._getInputEl().focus()
            field._getInputEl().set('value', 'setByInputEl')
            field._inputElOnChange();//simulate onChange event, TODO: see if Y.simulate could do the job
            //field._getInputEl().blur()
            Y.Assert.areEqual('setByInputEl', field.get('value'))
        },

        XLastFunction:{}
    })

    Y.inputEx.tests.DevTests = new Y.Test.Case({
        name: 'Development Tests',
        setUp:function() {
            this.data = {
                createTextField:  function(container) {
                    var field = Y.Node.create('<input id="' + this.getID() + '-field" type="text"/>')
                    if (this.get('name')) field.set('name', this.get('name'))
                    if (this.get('value')) field.set('value', this.get('value'))
                    container.appendChild(field)
                    this._inputEl = field
                }
            }
            Y.get('#test').set('innerHTML', '')
        },
        tearDown:function() { delete this.data; },
        XLastFunction:function() {}
    })

    //TODO: https://sourceforge.net/tracker2/?func=detail&atid=836476&aid=2431381&group_id=165715
    var console = new Y.Console()
    console.get('contentBox').setStyle('width', (Y.get('body').get('docWidth') * 3 / 4) + 'px')
    console.render()
    console.get('contentBox').query('div .yui-console-bd').setStyle('height', (Y.get('body').get('docHeight') * 4 / 5) + 'px')
    console.on('entry', function(e) {if (e.message.source !== 'TestRunner') { e.preventDefault()} })

    Y.Test.Runner.add(Y.inputEx.tests.DevTests);
    if (!Y.inputEx.any(Y.inputEx.tests.DevTests, function(v, k) { return /^test/.test(k) })) {
        // if there are any development tests, normal test won't run
        Y.Test.Runner.add(Y.inputEx.tests.FieldTests);
    }
    Y.Test.Runner.run();
})
</script>
</body>

</html>
